import clr
import sys
clr.AddReference('FSharp.Core')
clr.AddReference('System.Core')
clr.AddReferenceToFileAndPath('abcexplorationlib.dll')

import System
from System.IO import *
from Langexplr.Abc import *

#from System.Diagnostics import *
#Debugger.Break()

def printTrait(t):
   print "\t\tMetadata entries: " + t.metadata.Length.ToString()
   if t.traitType.IsTraitSlot:
      print  "\t\tslotId = "+t.traitType.Item1.ToString()
      print  "\t\ttypeName = "+t.traitType.Item2.ToString()
      print  "\t\tvIndex = "+t.traitType.Item3.ToString()
      print  "\t\tvKind = "+t.traitType.Item4.ToString()
   if t.traitType.IsTraitClass:
      print  "\t\tslotId = "+t.traitType.Item1.ToString()
      print  "\t\tclassIndex = "+t.traitType.Item2.ToString()
   if t.traitType.IsTraitMethod:
      print  "\t\tslotId = "+t.traitType.Item1.ToString()
      print  "\t\tmethod = "+t.traitType.Item2.ToString()

   else:
     pass


def formatInstr(i,args):
   return "   "+i.Name + " "+args

def formatJumpOffset(o):
   if o.IsUnSolvedReference:
      return o.Item.ToString()
   elif o.IsSolvedReference:
      return o.Item.ToString()
   else:
      return ""
     

instructionHelpers = {
   'hasnext2' : lambda(i): formatInstr(i, i.Item1.ToString()+","+i.Item2.ToString()),
   'findpropertystrict' : lambda(i): formatInstr(i, i.Item.ToString()),
   'getproperty' : lambda(i): formatInstr(i, i.Item.ToString()),
   'getlex' : lambda(i): formatInstr(i, i.Item.ToString()),
   'newclass' : lambda(i): formatInstr(i, i.Item.ToString()),
   'pushstring': lambda(i): formatInstr(i, "\"" +i.Item.ToString() + "\""),
   'callprop' : lambda(i): formatInstr(i,i.Item1.ToString()),
   'callpropvoid' : lambda(i): formatInstr(i,i.Item1.ToString()),
   'callsuper' : lambda(i): formatInstr(i,i.Item1.ToString()),
   'iftrue': lambda (i): formatInstr(i, formatJumpOffset(i.Item)),
   'iffalse': lambda (i): formatInstr(i, formatJumpOffset(i.Item)),
   'iflt': lambda (i): formatInstr(i, formatJumpOffset(i.Item)),
   'ifstrictneq': lambda (i): formatInstr(i, formatJumpOffset(i.Item)),
   'jump': lambda (i): formatInstr(i, formatJumpOffset(i.Item)),
   'setslot': lambda (i): formatInstr(i, i.Item.ToString()),
   'getslot': lambda (i): formatInstr(i, i.Item.ToString()),
   'pushbyte': lambda (i): formatInstr(i, i.Item.ToString()),
   'pushshort': lambda (i): formatInstr(i, i.Item.ToString()),
   'pushdouble': lambda (i): formatInstr(i, i.Item.ToString()),
   'pushint': lambda (i): formatInstr(i, i.Item.ToString()),
   'ArtificialJumpLabel': lambda (i): i.Item.ToString() + ":",
   "lookupswitch": lambda(i): formatInstr(i,formatJumpOffset(i.Item1)+" "+
                                            ",".join([formatJumpOffset(o) for o in i.Item2]))
  }


def instructionToString(i):
  if i.Name in instructionHelpers:
     return instructionHelpers[i.Name](i)
  else:
     return formatInstr(i,"")


dataStream = FileStream(sys.argv[1],FileMode.Open)
reader = BinaryReader(dataStream)
abcFile  = AbcFile.ReadFrom(reader)
dataStream.Close()


print "Scripts: "+abcFile.Scripts.Length.ToString() 
print "Classes: "+abcFile.Classes.Length.ToString() 
print "Instances: "+abcFile.Instances.Length.ToString() 
print "Methods: "+abcFile.Methods.Length.ToString() 
print "MethodBodies: "+abcFile.MethodBodies.Length.ToString() 
print "Metadata: "+abcFile.Metadata.Length.ToString() 

print "Constant pool:"

cp = abcFile.ConstantPool

print "\tIntegers:"
for i in cp.Integers:
   print "\t\t"+i.ToString()

print "\tUnsigned integers:"
for i in cp.UnsignedIntegers:
   print "\t\t"+i.ToString()

print "\tDoubles:"
for i in cp.Doubles:
   print "\t\t"+i.ToString()

print "\tStrings:"
for i in cp.Strings:
   print "\t\t"+'"'+i.ToString()+'"'

print "\tNamespaces:"

for ns in cp.Namespaces:
   print "\t\t"+ns.ToString()

print "\tNamespace Sets:"
for ns in cp.NamespaceSets:
   print "\t\t"+ns.ToString()

print "\tNamespace Sets(Solved):"
for ns in cp.NamespaceSets:
   namespacesNames = [cp.SolveNamespaceName(n).ToString() for n in ns.ns]
   namespacesNames.sort()
   print "\t\t{"+("\n\t\t\t".join(namespacesNames  ))+"}"


print "\tMultinames:"
for mn in cp.Multinames:
   print "\t\t"+mn.ToString()

print "Classes"

for c in abcFile.Classes:
   print "Class " + c.cInit.ToString()
   for t in c.traits:
      print "\t name: %d\n\t type: %s" % (t.name,t.traitType.ToString())
      print "\t atts: %d"  % (t.attributes)

print ""

print "Instances"


for i in abcFile.Instances:
   print "\tInstance " + i.name.ToString() + " - " + abcFile.ConstantPool.SolveMultiName(i.name).ToString()
   print "\t\tIInit " + i.iInit.ToString()
   print "\t\tSuperclass " + i.superName.ToString() + " - " + abcFile.ConstantPool.SolveMultiName(i.superName).ToString()
   print "\t\tFlags  " + i.flags.ToString()
   print "\t\tProtected namespace  " + i.protectedNs.ToString() + " - " + abcFile.ConstantPool.SolveNamespaceName(i.protectedNs).ToString()
   print "\t\tInterfaces " 
   for intr in i.interfaces:
     print "\t" + i.ToString()
   print "\t\tTraits  " 
   for t in i.traits:
      print "\t name: %d\n\t type: %s -- %s" % (t.name,t.traitType.ToString(),abcFile.ConstantPool.SolveMultiName(t.name).ToString()) 
      print abcFile.ConstantPool.SolveMultiName(t.name).GetType().ToString()
      printTrait(t)
      print "\t attributes = %s" % (t.attributes) 

print ""

print "Scripts"

for s in abcFile.Scripts:
   print "Script " + s.InitMethod.ToString()
   for t in s.traits:
      #print "\t name: %d\n\t type: %s" % (t.name,t.traitType.ToString())
      print "\t name: %d\n\t type: %s -- %s" % (t.name,t.traitType.ToString(),abcFile.ConstantPool.SolveMultiName(t.name).ToString()) 
      printTrait(t)

print ""



print "Methods" 

for m in abcFile.Methods:
  print "\nMethod "
  print "Name: "+ m.name.ToString() + " - " + abcFile.ConstantPool.GetString(m.name).ToString()
  print "Flags: "+m.flags.ToString()
  print "Return type: "+m.returnType.ToString() + " - " + abcFile.ConstantPool.SolveMultiName(m.returnType).ToString()
  print "Parameters: " + ",".join([x.ToString() for x in m.paramType])
  print "Options: " + m.options.count.ToString()



for mb in abcFile.MethodBodies:
  template = """
Method: %(method)d
Max stack: %(maxstack)d
Local count: %(localcount)d
Init scope depth: %(initscopedepth)d
Max scope depth: %(maxscopedepth)d""" % \
   {'method':mb.MethodId,'maxstack':mb.MaxStack,
    'localcount':mb.LocalCount,'initscopedepth':mb.InitScopeDepth,
    'maxscopedepth':mb.MaxScopeDepth}
  classNames = [cp.SolveMultiName(i.name) for i in abcFile.Instances]
  print template
  print "Instructions:"
  avmBody = AvmMethodBody.Create(mb,cp,System.Array[QualifiedName](classNames))
  for i in avmBody.Instructions:
     print "\t" + instructionToString(i)

